package org.sosie2.service.framework;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.URL;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Properties;

import javax.xml.soap.MessageFactory;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.axis.Message;
import org.apache.axis.message.SOAPBody;
import org.apache.axis.utils.XMLUtils;
import org.apache.log4j.Logger;
import org.apache.xml.security.c14n.Canonicalizer;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

/**
 * Various functions and constants for the whole framework.
 * @author Gabriela
 *
 */
public class Utils {   
	public static final String LOGGER_FILE = "logger.config";
	public static final String LOG = "log.txt";
	
    public static final String NS = "http://www.unibw.de/";	
	public static final String PREFIX = "ws";
	public static final String LN_ANNOTATION = "Annotation";
	public static final String LN_COMMON_ANNOTATION = "CommonAnnotation";
	public static final String LN_PAIR_ANNOTATION = "AttributePairAnnotation";
	
	public static final String ACTOR = "http://www.unibw.de/sosie2/theaterActor";
	
	// To be defined in each service
	public static final String AUTH_ACTOR = "theatherActor/authentication";
	public static final String AUTH_AUTHOR = "theatherActor/authenticationAuthor";
	public static final String AUTHO_AUTHOR = "theatherActor/autorizationAuthor";	
	
	// To be defined in the respective service
	public static final String ALERT_CONFIG="configuration/alert.properties";
	public static final String MAILSERVER_SETTINGS="configuration/mailserver.properties";
	public static final String CONFIG_ALERT="configuration/config.properties";
	
	public static final String AUTHENTICATION_FILE="configuration/users.properties";
	// To be defined in the respective service
	public static final String LDAP_SERVER = "localhost:389";
	public static final String ldap_args = "localhost:389 " + "ou=simple,ou=people,dc=guessant,dc=org"+"cn=Sinbad Marinarul,ou=simple,ou=people,dc=guessant,dc=org"+"jRj";
	public static final String LDAP_DOMAIN = "ou=simple,ou=people,dc=guessant,dc=org";
    
    public static final String emptySoapMsg = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"><SOAP-ENV:Body></SOAP-ENV:Body></SOAP-ENV:Envelope>";
    
    
    private static Utils singleton = null;
	
    
	public Utils() {		
	}
	
	
	public static Utils get() {
		if (singleton == null) 
			singleton = new Utils();
		return singleton;
	}
    
    /**
     * Writes a Document to a logger or to the console.
     * 
     * @param s
     * @param d
     * @param logger
     * @throws Exception
     */
    public static void dumpXML(String s, Document d, Logger logger) throws Exception {
		// Dump response
		Transformer transformer = TransformerFactory.newInstance().newTransformer();
		transformer.setOutputProperty(OutputKeys.INDENT, "yes");
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		transformer.transform(new DOMSource(d), new StreamResult(baos));
		
		if (logger != null) {
			logger.info(s);
			logger.info(baos.toString());
		} else {
			System.out.println(baos.toString());
		}
	}
	
    /**
     * Document to SOAPMessage
     * 
     * @param doc
     * @return
     * @throws Exception
     */
	public static SOAPMessage toMessage(Document doc) throws Exception {
		Canonicalizer c14n = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
		byte[] canonicalMessage = c14n.canonicalizeSubtree(doc);
		ByteArrayInputStream in = new ByteArrayInputStream(canonicalMessage);
		MessageFactory factory = org.apache.axis.soap.MessageFactoryImpl.newInstance();
		return factory.createMessage(null, in);        
	}
	
	
	/**
	 * Document to String
	 * 
	 * @param d
	 * @return
	 * @throws Exception
	 */
	public static String getDocumentAsString(Document d) throws Exception
	{
		Transformer transformer = TransformerFactory.newInstance().newTransformer();
		transformer.setOutputProperty(OutputKeys.INDENT, "yes");
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		transformer.transform(new DOMSource(d), new StreamResult(baos));
		return baos.toString();
	}
    
	
	/**
	 * Creates a SOAP Message with the specified body content.
	 * 
	 * @param bodyString The content of the SOAP body
	 * @return
	 * @throws Exception
	 */
    public static Message createMessage(String bodyString) throws Exception {	
    	InputStream in = new ByteArrayInputStream(Utils.emptySoapMsg.getBytes());
		Message msg = new Message(in);
		
		if (bodyString == "") return msg;
		
		StringReader strReader = new StringReader(bodyString);		
		
		Document document = XMLUtils.newDocument(new InputSource(strReader));
		// Add request to SOAP body
		SOAPBody body = (SOAPBody) msg.getSOAPBody();					
		body.addDocument(document);
    	
    	return msg;    	
    }
    
    
	public Properties getResource(String name) throws Exception 
	{
		Properties props = new Properties();
		if (name == null)
		{
			throw new Exception("Null parameter for configuration file!");
		}
		else 
			System.out.println("Name = " +name);
		URL url = getFile(name);
		if (url == null)
		{
			throw new Exception("Null URL for configuration file");	
		}
		
		try{
			InputStream is = url.openStream();
			props.load(is);
		}catch(Exception ee)
		{
			ee.printStackTrace();
		}
		
		return props;
	}	
	
	
	public URL getFile(String name) {
		if (name == null) 
			return   null;
		URL url = getClass().getClassLoader().getResource(name);
		
		if (url == null) {
			// ... search somewhere else
		}
		
		return url;
	}
	
	
	/**
	 * 1rst param = tag name
	 * 2nd  param = namespace name
	 * 3rd  param = namespace url
	 * 4th  param = some text node 
	 * 
	 * @param headerString
	 * @param msg
	 * @return a Message object with header
	 * @throws SOAPException
	 * 
	 * @deprecated
	 */    
    public static Message addHeaderToHeaderlessMessage(String headerString[], Message msg) throws Exception {
    	
    	if (headerString.length != 4) {
    		System.out.println("Not enough header information for adding to the SOAPBody");
    		return null;
    	}
    	
    	
    	SOAPHeader header = msg.getSOAPEnvelope().getHeader();
    	SOAPFactory soapFactory = SOAPFactory.newInstance();
    	
    	Name headerName = soapFactory.createName(headerString[0], headerString[1], headerString[2]);
    	SOAPHeaderElement headerElement = header.addHeaderElement(headerName);
    	headerElement.addTextNode(headerString[3]);
    	headerElement.setMustUnderstand(false);
    	
    	return msg;
    }
    
	
	/**
	 * function for removing all nodes of the specified type and specified name
	 * If name is null, then the node is removed if the type matches.
	 * 
	 * @deprecated
	 */     
	public static void removeAll(Node node, short nodeType, String name) 
	{
		if (node.getNodeType() == nodeType && (name == null || node.getNodeName().equals(name))) 
		{
			node.getParentNode().removeChild(node);
	    } 
		else 
	    {
			// Visit the children
	        NodeList list = node.getChildNodes();
	        for (int i=0; i<list.getLength(); i++) 
	        {
	        	removeAll(list.item(i), nodeType, name);
	        }
	    }
	 }
}


